﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;

namespace Comun {
    public enum enuHeader {
        REQ,
        RES
    }
    public enum enuOrden {
        Sesion = 1,
        AmigosBloqueados = 2,
        AmigosNoBloqueados = 3,
        SolicitarAmistad = 4,
        AgregarEstado = 5,
        Ping = 6,
        ComentarEstado = 7,
        QuitarEstado = 8,
        EstadosAmigo = 9,
        TextoEstado = 10,
        ComentariosEstado = 11,
        TextoComentario = 12,
        UsuarioQueComenta = 13,
        Cerrar = 14,
        BloquearAmigo = 15,
        DesbloquearAmigo = 16
    }

    public class Comando {
        public const char SEPARADOR = ';';
        public const int TAMANNO_ENCABEZADO = 10;

        private enuHeader encabezado;

        public enuHeader Encabezado {
            get { return encabezado; }
            set { encabezado = value; }
        }
        private enuOrden orden;

        public enuOrden Orden {
            get { return orden; }
            set { orden = value; }
        }
        private int largo;

        public int Largo {
            get { return largo; }
            set { largo = value; }
        }
        private List<string> parametros;

        public List<string> Parametros {
            get { return parametros; }
            set { parametros = value; }
        }

        public Comando() {
            parametros = new List<string>();
        }

        public Comando(string texto) {
            parametros = new List<string>();
            parsear(texto);
        }

        public void Parse(string texto) {
            parsear(texto);
        }

        public void parsear(string texto) {
            if (texto.Length < TAMANNO_ENCABEZADO) {
                throw new Exception("Error parseo, encabezado muy corto");
            } else {
                if (texto.Substring(0, 3) == "REQ") {
                    encabezado = enuHeader.REQ;
                } else if (texto.Substring(0, 3) == "RES") {
                    encabezado = enuHeader.RES;
                } else {
                    throw new Exception("Error parseo, header incorrecto");
                }
                int int_orden;
                if (!int.TryParse(texto.Substring(3, 2), out int_orden)) {
                    throw new Exception("Error parseo, comando no es entero");
                }
                try {
                    this.orden = (enuOrden)int_orden;
                } catch {
                    throw new Exception("Error parseo, comando desconocido");
                }
                if (!int.TryParse(texto.Substring(5, 5), out largo)) {
                    throw new Exception("Error parseo, largo no es entero");
                }
            }
        }

        public override string ToString() {
            largo = 0;
            string str_parametros = "";
            foreach (string s in parametros) {
                largo += s.Length;
                if (str_parametros == "") {
                    str_parametros = s;
                } else {
                    largo++;
                    str_parametros += Comando.SEPARADOR.ToString() + s;
                }
            }
            string str_encabezado = (this.Encabezado == enuHeader.REQ ? "REQ" : "RES") + ((int)orden).ToString("00") + Largo.ToString("00000");
            return str_encabezado + str_parametros;
        }

        public void AsignarParametros(string texto) {
            parametros.Clear();
            foreach (string s in texto.Split(SEPARADOR)) {
                parametros.Add(s);
            }
        }

        public byte[] ObtenerBytes() {
            return Encoding.UTF8.GetBytes(this.ToString());
        }

        public static Comando ObtenerComando(NetworkStream stream) {
            Comando comando = new Comando();

            string encabezado = ObtenerDeStream(stream, Comando.TAMANNO_ENCABEZADO);

            comando.parsear(encabezado);

            if (comando.Largo > 0) {
                string parametros = ObtenerDeStream(stream, comando.Largo);

                comando.AsignarParametros(parametros);
            }

            return comando;
        }

        private static string ObtenerDeStream(NetworkStream stream, int cantidad) {
            byte[] bytesFrom = new byte[cantidad];
            int bytes_recibidos = 0;
            while (bytes_recibidos < cantidad) {
                bytes_recibidos += stream.Read(bytesFrom, bytes_recibidos, cantidad - bytes_recibidos);
            }
            return Encoding.UTF8.GetString(bytesFrom);
        }

        public void Enviar(NetworkStream stream) {
            byte[] buffer_comando = ObtenerBytes();

            stream.Write(buffer_comando, 0, buffer_comando.Length);
        }

    }
}
